package game;

import game.efekti.EffectFactory;
import game.efekti.IncHealth;
import game.efekti.IncMana;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import javax.imageio.ImageIO;

import util.INIGroup;
import util.Util;
import GUI.ImageStorage;


public class Item implements Loadable, Cloneable{
	public enum ItemType{WEAPON, SHIELD, ARMOR, HELMET, POTION, CHARM, SPECIAL};
	private static final int EFFECT_CHANCE = 20, MAX_EFFECTS = 5;
	private static final double LEVEL_FACTOR = 30.0;
	
	String tag;
	String description;
	String name;
	String imgName;
	Character owner;
	int posX;
	int posY;
	int weight;
	int maxHealth;
	int health;
	int minDamage;
	int maxDamage;
	int lvlRequired;
	int armor;
	int healingPower;
	TileMap map;
	BufferedImage image = null;
	Vector<String> effectTags = null;
	ArrayList<MagicEffect> efects  = new ArrayList<MagicEffect>();
	//static HashMap<String, BufferedImage> images = null;
	boolean mana;
	boolean ranged;
	boolean twoHanded;
	ItemType type;
	public BufferedImage getImage() {
		if (image == null){
			this.image = ImageStorage.getImage("GUI/default-img.png");
		}
		return image;
	}
	public void setImage(BufferedImage image) {
		this.image = image;
	}
	public int getxPos() {
		return posX;
	}
	public void setxPos(int xPos) {
		this.posX = xPos;
	}
	public int getyPos() {
		return posY;
	}
	public void setyPos(int yPos) {
		this.posY = yPos;
	}
	public TileMap getMap() {
		return map;
	}
	public void setMap(TileMap map) {
		this.map = map;
	}
	public String getTag() {
		return tag;
	}
	public ArrayList<MagicEffect> getEffects() {
		return efects;
	}
	public boolean isRanged() {
		return ranged;
	}
	public boolean isTwoHanded() {
		return twoHanded;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Character getOwner() {
		return owner;
	}
	public void setOwner(Character owner) {
		this.owner = owner;
	}
	public int getHealth() {
		return health;
	}
	public void setHealth(int health) {
		this.health = health;
	}
	public int getMinDamage() {
		return minDamage;
	}
	public void setMinDamage(int minDamage) {
		this.minDamage = minDamage;
	}
	public int getMaxDamage() {
		return maxDamage;
	}
	public void setMaxDamage(int maxDamage) {
		this.maxDamage = maxDamage;
	}
	public int getLvlRequired() {
		return lvlRequired;
	}
	public void setLvlRequired(int lvlRequired) {
		this.lvlRequired = lvlRequired;
	}
	public int getArmor() {
		return armor;
	}
	public void setArmor(int armor) {
		this.armor = armor;
	}
	public int getHealingPower() {
		return healingPower;
	}
	public void setHealingPower(int healingPower) {
		this.healingPower = healingPower;
	}
	public boolean isMana() {
		return mana;
	}
	public void setMana(boolean mana) {
		this.mana = mana;
	}
	public ItemType getType() {
		return type;
	}
	
	/*
	private static void initGroup(String n)
	{
		Vector<String> g = GameBase.getList(n);
		if (g != null){
			for (String s: g){
				BufferedImage img = ImageStorage.getImage("GameGFX/Items" + File.separator + s + ".png");
				if(img != null) images.put(s, img);
			}
		}
	}
	*/
	
	/*
	private static void initImages(){
		images = new HashMap<String, BufferedImage>();
		initGroup("hamajlijaImgs");
		
		initGroup("kabalImgs");
		initGroup("lukicImgs");
		initGroup("pritkaImgs");
		initGroup("kamenicaImgs");
		initGroup("pecinaImgs");
		
		initGroup("maljutkaImgs");
		initGroup("letvaImgs");
		initGroup("macinaImgs");
		initGroup("nozinaImgs");
		initGroup("sikiraImgs");
		
		initGroup("poijsn_manaImgs");
		initGroup("poijsn_healthImgs");
		
		initGroup("tavaImgs");
		initGroup("zastitaImgs");
		initGroup("zaklonImgs");
		
		initGroup("skalamerijaImgs");
		initGroup("sasijaImgs");
		initGroup("cebeImgs");
		
		initGroup("cunjImgs");
		initGroup("lonacImgs");
		initGroup("kanticaImgs");
		
	}
	*/
	
	public static Item genItem(int lvl){
		Item itm = new Item();
		int itmType = Util.getRndInt(0, 5);
		String stype = "";
		int minEff = 0, maxEff = 0;
		
		switch (itmType){
			case 0:
				itm.type = ItemType.WEAPON;
				itm.weight = 90;
				itm.maxHealth = Util.getRndInt(6+lvl*3)+10;
				itm.health = Util.getRndInt((int)(20.0/100.0*itm.maxHealth), (int)(80.0/100.0*itm.maxHealth));
				itm.ranged = Util.getRndInt(2) == 1;
				if (!itm.ranged)
					itm.twoHanded = Util.getRndInt(2) == 1;
				itm.minDamage = Util.getRndInt(lvl*4)*5+20;
				itm.maxDamage = Util.getRndInt(20)+itm.minDamage+1;
				
				if (itm.ranged)
					stype = GameBase.getRndFromList("rangedWeaponTypes");
				else
					stype = GameBase.getRndFromList("meleeWeaponTypes");
				
				minEff = 0;
				maxEff = MAX_EFFECTS;
				break;
				
			case 1:
				itm.type = ItemType.POTION;
				itm.weight = 10;
				itm.mana = Util.getRndInt(2) == 1;
				
				if (itm.mana){ 
					stype = GameBase.getRndFromList("manaPotionTypes");
					IncMana inm = new IncMana();
					inm.generateForLevel(lvl);
					itm.efects.add(inm);
				}
				else {
					stype = GameBase.getRndFromList("healthPotionTypes");
					IncHealth inh = new IncHealth();
					inh.generateForLevel(lvl);
					itm.efects.add(inh);
				}
				
				minEff = 0;
				maxEff = 0;
				break;
				
			case 2:
				itm.type = ItemType.SHIELD;
				itm.weight = 70;
				itm.maxHealth = Util.getRndInt(6+lvl*3)+10;
				itm.health = Util.getRndInt((int)(20.0/100.0*itm.maxHealth), (int)(80.0/100.0*itm.maxHealth));
				itm.armor = Util.getRndInt(3+lvl*2)+3;
				
				stype = GameBase.getRndFromList("shieldTypes");
				minEff = 0;
				maxEff = MAX_EFFECTS;
				break;
			case 3:
				itm.type = ItemType.CHARM;
				itm.weight = 10;
				
				stype = GameBase.getRndFromList("charmTypes");
				minEff = 1;
				maxEff = MAX_EFFECTS;
				break;
			case 4:
				itm.type = ItemType.ARMOR;
				itm.weight = 140;
				itm.maxHealth = Util.getRndInt(6+lvl*3)+10;
				itm.health = Util.getRndInt((int)(20.0/100.0*itm.maxHealth), (int)(80.0/100.0*itm.maxHealth));
				itm.armor = Util.getRndInt(1+lvl*2)+ 3;
				
				stype = GameBase.getRndFromList("armorTypes");
				minEff = 0;
				maxEff = MAX_EFFECTS;
				break;
			case 5:
				itm.type = ItemType.HELMET;
				itm.weight = 50;
				itm.maxHealth = Util.getRndInt(6+lvl*3)+10;
				itm.health = Util.getRndInt((int)(20.0/100.0*itm.maxHealth), (int)(80.0/100.0*itm.maxHealth));
				itm.armor = Util.getRndInt(1+lvl*2)+ 3;
				
				stype = GameBase.getRndFromList("helmetTypes");
				minEff = 0;
				maxEff = MAX_EFFECTS;
				break;
		}
		
		genEffect(itm.type, lvl, (int) ((double)EFFECT_CHANCE * (1.0 + (lvl / LEVEL_FACTOR))), minEff, maxEff, itm);
		itm.name = GameBase.getString(stype);
		itm.image = ImageStorage.getImage("GameGFX/Items/" + 
				GameBase.getRndFromList(stype.toLowerCase() + "Imgs") + ".png");
		
		if(itm.type != ItemType.POTION)
		{
			if(itm.efects.size() == 0)
				itm.name = GameBase.getRndFromList("itemVulgarisPrefix") + " " + itm.name;
			else if(itm.efects.size() == 1)
				itm.name = GameBase.getRndFromList("itemPrefix") + " " + itm.name;
			else if(itm.efects.size() == 2)
				itm.name = itm.name + " Of " + GameBase.getRndFromList("itemPostfix");
			else
				itm.name = GameBase.getRndFromList("itemPrefix") + " " + itm.name + " Of " + 
					GameBase.getRndFromList("itemPostfix");
		}
		
		return itm;
		
	}
	public String toString(){
		String ret;
		ret = "ime: " + this.name + "\n";
		ret += "-------------------------" + "\n";
		ret += "opis: " + this.description  + "\n";
		ret += "tezina: " + this.weight + "\n";
		ret += "tip: " + this.type + "\n";
		if (this.type == ItemType.ARMOR || this.type == ItemType.SHIELD || this.type == ItemType.HELMET){
			ret += "armor: "+ this.armor + "\n";
			ret += "health: " + this.health + "/"+ this.maxHealth+ "\n";
			ret += "efekti: \n";
			for(MagicEffect e : this.efects){
				ret += e+ "\n";
			}
		}
		if (this.type == ItemType.POTION){
			ret += "efekat: "  + this.efects.get(0) + "\n";
		}
		if (this.type == ItemType.WEAPON){
			ret += "jel ranged: " + this.ranged + "\n";
			ret += "damage: " + this.minDamage + " - " + this.maxDamage + "\n";
			ret += "health: " + this.health + "/"+ this.maxHealth+ "\n";
			ret += "two handed: " + this.twoHanded + "\n";
			ret += "efekti: \n";
			for(MagicEffect e : this.efects){
				ret += e+ "\n";
			}
		}
		if (this.type == ItemType.CHARM){
			ret += "efekti: \n";
			for(MagicEffect e : this.efects){
				ret += e+ "\n";
			}
		}
		return ret;
	}
	
	public String getHTML()
	{
		StringBuilder sb = new StringBuilder();
		
		sb.append("<p color=FFFFFF align=center>");
		if(this.type != ItemType.POTION && this.efects.size() > 0)
			sb.append("<b><span color=5050FF>" + this.name.toUpperCase() + "</span></b><br />");
		else
			sb.append("<b>" + this.name.toUpperCase() + "</b><br />");
		
		sb.append("<b><span color=808000>(" + this.type.toString().toLowerCase() + " class)</span></b><br />");
		if(this.description != null)
			if(this.description.length() > 0)
				sb.append("<i>" + this.description + "</i></b>");
		if(lvlRequired > 0)
			sb.append("Required level : " + this.lvlRequired + "<br />");
		
		if (this.type == ItemType.ARMOR || this.type == ItemType.SHIELD || this.type == ItemType.HELMET)
		{
			sb.append("<b><span color=50FF50>Defense rating : " + this.armor + "</span></b><br />");
			sb.append("Durability : " + this.health + " of " + this.maxHealth + "<br />");
		}
		else if (this.type == ItemType.WEAPON){
			sb.append("<b><span color=50FF50>Damage : " + this.minDamage + " to " + this.maxDamage + "</span></b><br />");
			if(this.ranged)
				sb.append("<b>Ranged weapon</b><br />");
			if(this.twoHanded)
				sb.append("<b>Two-handed weapon</b><br />");
			
			sb.append("Durability : " + this.health + " of " + this.maxHealth + "<br />");
		}
		
		for(MagicEffect e : this.efects)
			sb.append("<span color=5050FF><b>" + e.toString() + "</b></span><br />");
		
		sb.append("Weight : " + this.weight + "<br />");
		sb.append("</p>"); return sb.toString();
	}
	
	@Override
	public boolean loadFromFile(INIGroup group) {
		this.tag = group.vals.get("tag");
		effectTags = new Vector<String>();
		effectTags.add(group.getString("effect1"));
		effectTags.add(group.getString("effect2"));
		effectTags.add(group.getString("effect3"));
		effectTags.add(group.getString("effect4"));
		effectTags.add(group.getString("effect5"));
		this.name = group.vals.get("name");
		this.imgName = group.vals.get("imgName");
		this.description = group.getString("description", "Nema opisa!");
		this.weight = group.getInteger("weight");
		try
		{
			this.type = ItemType.valueOf(group.getString("type"));
		} 
		catch(Exception e) 
		{ 
			this.type = ItemType.SPECIAL; 
			System.out.println("Item \"" + tag + "\" doesn't have a type!");
		}
		
		if (this.type == ItemType.ARMOR || this.type == ItemType.SHIELD || this.type == ItemType.HELMET){
			this.armor = group.getInteger("armor");
			this.maxHealth = this.health = group.getInteger("health");
		}
		if (this.type == ItemType.POTION){
			this.mana = "true".equals(group.getString("mana"));
			this.healingPower = group.getInteger("healingPower");
		}
		if (this.type == ItemType.WEAPON){
			this.ranged = "true".equals(group.getString("ranged"));
			this.maxHealth = this.health = group.getInteger("health");
			this.minDamage = group.getInteger("minDamage");
			this.maxDamage = group.getInteger("maxDamage");
			this.twoHanded = "true".equals(group.getString("twoHanded"));
		}
		return true;
	}
	public Item clone() throws CloneNotSupportedException{
		Item i = (Item)(super.clone());
		i.owner = null;
		i.efects = new ArrayList<MagicEffect>();
		for(MagicEffect e : efects)
			if(e != null)
				i.efects.add(e.clone());
		return i;
	}
	static void genEffect(ItemType t, int l, Item it){
		MagicEffect e1 = null, e2 = null;
		if (Util.chance(20)) e1 = EffectFactory.getEffectForLevel(t, l);
		if (Util.chance(20)) e2 = EffectFactory.getEffectForLevel(t, l);
		if (e1 != null && e2 != null) {
			if (e1.getClass() != e2.getClass()){
				it.efects.add(e1);
				it.efects.add(e2);
			}
		}
		else {
			if (!(e1==null))it.efects.add(e1);
			else if (!(e2 == null)) it.efects.add(e2);
		}
	}
	
	static void genEffect(ItemType t, int l, int effChance, int minEff, int maxEff, Item it){
		for(int i = 0; i < minEff; ++i)
			it.addEffect(EffectFactory.getEffectForLevel(t, l));
		for(int i = minEff; i < maxEff; ++i)
			if(Util.chance(effChance)) it.addEffect(EffectFactory.getEffectForLevel(t, l));
	}
	
	public void addEffect(MagicEffect ae)
	{
		if(ae == null) return;
		for(MagicEffect e : efects)
		{
			if(e.stacksWith(ae))
			{
				System.out.print("Absorbtion! " + ae + " + " + e);
				e.absorb(ae);
				System.out.println(" = " + e);
				return;
			}
		}
		efects.add(ae);
	}
	@Override
	public void init() {
		for (String s : effectTags){
			if (!(s.equals(""))) efects.add(GameBase.getEffectByTag(s));
		}
		if(this.imgName != null)
		{
			if (!this.imgName.equals("")) {
				try {
					this.image = ImageIO.read(new File("Items" + File.separator + this.imgName + ".png"));
				} catch (IOException e) {}
			}
		}
	}
	

}
